Tratamiento Digital de Imágenes
2025-02-19
\[ g(x,y) = T[f(x,y)] \]
donde:
Lineales:
No lineales:
La forma más simple de ajustar brillo y contraste:
\[ g(x,y) = \alpha \cdot f(x,y) + \beta \]
donde:
import cv2
import matplotlib.pyplot as plt
import numpy as np
# Cargar imagen en escala de grises
img = cv2.imread("imagenes/DPP0357.TIF", cv2.IMREAD_GRAYSCALE)
# Diferentes valores de brillo (beta)
brillo_oscuro = cv2.convertScaleAbs(img, alpha=1.0, beta=-50)
brillo_original = img
brillo_claro = cv2.convertScaleAbs(img, alpha=1.0, beta=50)
# Visualización
plt.figure(figsize=(12,4))
plt.subplot(1,3,1)
plt.imshow(brillo_oscuro, cmap='gray')
plt.title('β = -50 (más oscuro)')
plt.axis('off')
plt.subplot(1,3,2)
plt.imshow(brillo_original, cmap='gray')
plt.title('β = 0 (original)')
plt.axis('off')
plt.subplot(1,3,3)
plt.imshow(brillo_claro, cmap='gray')
plt.title('β = +50 (más claro)')
plt.axis('off')
plt.tight_layout()
plt.show()# Diferentes valores de contraste (alpha)
contraste_bajo = cv2.convertScaleAbs(img, alpha=0.5, beta=0)
contraste_original = img
contraste_alto = cv2.convertScaleAbs(img, alpha=1.5, beta=0)
# Visualización
plt.figure(figsize=(12,4))
plt.subplot(1,3,1)
plt.imshow(contraste_bajo, cmap='gray')
plt.title('α = 0.5 (bajo contraste)')
plt.axis('off')
plt.subplot(1,3,2)
plt.imshow(contraste_original, cmap='gray')
plt.title('α = 1.0 (original)')
plt.axis('off')
plt.subplot(1,3,3)
plt.imshow(contraste_alto, cmap='gray')
plt.title('α = 1.5 (alto contraste)')
plt.axis('off')
plt.tight_layout()
plt.show()# Combinando alpha y beta
ajustada = cv2.convertScaleAbs(img, alpha=1.3, beta=30)
# Visualización con histogramas
fig, axes = plt.subplots(2, 2, figsize=(12,8))
axes[0,0].imshow(img, cmap='gray')
axes[0,0].set_title('Original')
axes[0,0].axis('off')
axes[0,1].imshow(ajustada, cmap='gray')
axes[0,1].set_title('Ajustada (α=1.3, β=30)')
axes[0,1].axis('off')
axes[1,0].hist(img.ravel(), bins=256, color='gray', alpha=0.7)
axes[1,0].set_title('Histograma original')
axes[1,0].set_xlim([0,256])
axes[1,1].hist(ajustada.ravel(), bins=256, color='blue', alpha=0.7)
axes[1,1].set_title('Histograma ajustado')
axes[1,1].set_xlim([0,256])
plt.tight_layout()
plt.show()Problema:
- El ajuste lineal afecta uniformemente toda la imagen
- Puede saturar (valores >255 o <0)
- No diferencia entre tonos claros y oscuros
Solución:
- Transformaciones no lineales
- Ajustan diferentes rangos de intensidad de forma diferente
Transformación no lineal más común:
\[ g(x,y) = c \cdot [f(x,y)]^\gamma \]
donde:
Normalización en práctica: \[ g(x,y) = 255 \cdot \left(\frac{f(x,y)}{255}\right)^\gamma \]
\(\gamma < 1\) (por ejemplo, 0.5):
\(\gamma > 1\) (por ejemplo, 2.0):
\(\gamma = 1\):
# Función para aplicar corrección gamma
def ajustar_gamma(imagen, gamma=1.0):
# Crear tabla de búsqueda (LUT)
tabla = np.array([((i / 255.0) ** gamma) * 255
for i in range(256)]).astype("uint8")
# Aplicar la tabla
return cv2.LUT(imagen, tabla)
# Aplicar diferentes valores de gamma
gamma_05 = ajustar_gamma(img, gamma=0.5)
gamma_10 = img # Original
gamma_20 = ajustar_gamma(img, gamma=2.0)
# Visualización
plt.figure(figsize=(12,4))
plt.subplot(1,3,1)
plt.imshow(gamma_05, cmap='gray')
plt.title('γ = 0.5 (más claro)')
plt.axis('off')
plt.subplot(1,3,2)
plt.imshow(gamma_10, cmap='gray')
plt.title('γ = 1.0 (original)')
plt.axis('off')
plt.subplot(1,3,3)
plt.imshow(gamma_20, cmap='gray')
plt.title('γ = 2.0 (más oscuro)')
plt.axis('off')
plt.tight_layout()
plt.show()# Visualizar las curvas de transformación
x = np.linspace(0, 255, 256)
plt.figure(figsize=(10,6))
plt.plot(x, x, 'k--', label='γ = 1.0 (identidad)', linewidth=2)
plt.plot(x, 255 * (x/255)**0.5, 'b-', label='γ = 0.5', linewidth=2)
plt.plot(x, 255 * (x/255)**2.0, 'r-', label='γ = 2.0', linewidth=2)
plt.plot(x, 255 * (x/255)**0.3, 'g-', label='γ = 0.3', linewidth=2, alpha=0.6)
plt.xlabel('Intensidad de entrada', fontsize=12)
plt.ylabel('Intensidad de salida', fontsize=12)
plt.title('Curvas de corrección gamma', fontsize=14)
plt.legend(fontsize=10)
plt.grid(True, alpha=0.3)
plt.xlim([0, 255])
plt.ylim([0, 255])
plt.show()Negativo de imagen: \[ g(x,y) = 255 - f(x,y) \]
Útil para expandir valores oscuros y comprimir valores claros:
\[ g(x,y) = c \cdot \log(1 + f(x,y)) \]
# Transformación logarítmica
# Normalizar a [0,1], aplicar log, y escalar a [0,255]
img_normalizada = img.astype(np.float32) / 255.0
log_transformado = np.log1p(img_normalizada) # log1p es log(1+x)
# Normalizar resultado a [0,255]
log_transformado = (log_transformado / log_transformado.max()) * 255
log_transformado = np.uint8(log_transformado)
plt.figure(figsize=(10,4))
plt.subplot(1,2,1)
plt.imshow(img, cmap='gray')
plt.title('Original')
plt.axis('off')
plt.subplot(1,2,2)
plt.imshow(log_transformado, cmap='gray')
plt.title('Transformación logarítmica')
plt.axis('off')
plt.tight_layout()
plt.show()| Transformación | Cuándo usar | Ejemplo de aplicación |
|---|---|---|
| Ajuste lineal | Correcciones simples de brillo/contraste | Imagen ligeramente oscura |
| Gamma < 1 | Imágenes subexpuestas (muy oscuras) | Fotografía nocturna |
| Gamma > 1 | Imágenes sobreexpuestas (muy claras) | Imagen con flash excesivo |
| Logarítmica | Realzar detalles en zonas oscuras | Imágenes con alto rango dinámico |
| Negativo | Visualizar detalles oscuros | Radiografías médicas |
| Ecualización | Distribución desigual de intensidades | Mejorar contraste global |
# Crear una imagen de comparación
fig, axes = plt.subplots(2, 3, figsize=(15,8))
axes[0,0].imshow(img, cmap='gray')
axes[0,0].set_title('Original', fontsize=12)
axes[0,0].axis('off')
axes[0,1].imshow(cv2.convertScaleAbs(img, alpha=1.3, beta=30), cmap='gray')
axes[0,1].set_title('Ajuste lineal (α=1.3, β=30)', fontsize=12)
axes[0,1].axis('off')
axes[0,2].imshow(ajustar_gamma(img, 0.5), cmap='gray')
axes[0,2].set_title('Gamma = 0.5', fontsize=12)
axes[0,2].axis('off')
axes[1,0].imshow(ajustar_gamma(img, 2.0), cmap='gray')
axes[1,0].set_title('Gamma = 2.0', fontsize=12)
axes[1,0].axis('off')
axes[1,1].imshow(log_transformado, cmap='gray')
axes[1,1].set_title('Logarítmica', fontsize=12)
axes[1,1].axis('off')
axes[1,2].imshow(cv2.equalizeHist(img), cmap='gray')
axes[1,2].set_title('Ecualización', fontsize=12)
axes[1,2].axis('off')
plt.tight_layout()
plt.show()CIMAT – INFOTEC